import { isMobile } from '@utils'

const mobile = isMobile()

/* PC端 */

let startEl = null

function dragenter(e) {
  e.preventDefault()
}

function dragover(e) {
  e.preventDefault()
}

function drop(e) {
  e.preventDefault()
  const { __list, __index } = getDragEl(e.target)
  exchange(__list, __index, startEl.__index)
}

function dragstart(e) {
  startEl = e.target
}

function pcBind(el) {
  el.addEventListener('dragenter', dragenter)
  el.addEventListener('dragover', dragover)
  el.addEventListener('drop', drop)
  el.addEventListener('dragstart', dragstart)
}

function pcUnbind(el) {
  el.removeEventListener('dragenter', dragenter)
  el.removeEventListener('dragover', dragover)
  el.removeEventListener('drop', drop)
  el.removeEventListener('dragstart', dragstart)
}

/* 移动端 */

let moving = false
let timer = null

function dragStart() {
  moving = true
}

function dragEnd() {
  moving = false
}

function touchstart(e) {
  timer = setTimeout(dragStart, 500)

  const { changedTouches } = e
  const target = getDragEl(e.target)
  const first = changedTouches[0]
  const { clientX, clientY } = first
  target.__position = { x: clientX, y: clientY }
}

function touchmove(e) {
  timer && clearTimeout(timer)
  if (!moving) return

  e.preventDefault()

  const { changedTouches } = e
  const target = getDragEl(e.target)
  const first = changedTouches[0]
  const { x, y } = target.__position
  const { clientX, clientY } = first
  target.style.transform = `translate3d(${clientX - x}px, ${clientY - y}px, 0)`
}

function touchend(e) {
  if (!moving) return

  const target = getDragEl(e.target)
  target.style.transform = ''

  const { changedTouches } = e
  const first = changedTouches[0]
  const { pageX, pageY } = first
  const el = document.elementFromPoint(pageX, pageY)
  const endEl = getDragEl(el)

  if (!endEl) return

  const { __list, __index } = target
  exchange(__list, __index, endEl.__index)

  dragEnd()
}

function mobileBind(el) {
  el.addEventListener('touchstart', touchstart)
  el.addEventListener('touchmove', touchmove)
  el.addEventListener('touchend', touchend)
}

function mobileUnbind(el) {
  el.removeEventListener('touchstart', touchstart)
  el.removeEventListener('touchmove', touchmove)
  el.removeEventListener('touchend', touchend)
}

/* 拖拽指令 */

export default {
  bind(el, { arg, value }) {
    el.__list = arg
    el.__index = value
    el.draggable = true
    mobile ? mobileBind(el) : pcBind(el)
  },
  // vue 会复用dom，所以得更新一下
  update(el, { arg, value }) {
    el.__list = arg
    el.__index = value
  },
  unbind(el) {
    el.__list = null
    el.__index = null
    el.draggable = false
    mobile ? mobileUnbind(el) : pcUnbind(el)
  }
}

/* 工具方法 */

function getDragEl(el) {
  while (el) {
    if (el.__list) {
      return el
    }
    el = el.parentNode
  }
}

function exchange(list, indexA, indexB) {
  const temp = list[indexA]
  list.splice(indexA, 1, list[indexB])
  list.splice(indexB, 1, temp)
}
